
'use strict';


/**
	Part of Zombie Navigator
	Copyright © 2015  Zombie Navigator Developers
	
	@file
	@module
	@license AGPL-3.0+
*/


/*
	Public API
	NOTE: This is a pseudo-module used by a Zombie script, which runs
	unprivileged. It should be stable as well as secure.
*/


/* Used modules */
const _modBrowserWindow = require('../../platform/browser-window');


Object.freeze(Promise);
Object.freeze(Promise.prototype);
Object.freeze(Proxy);


/* Zombie API */

/**
	Get the module object for use in a Zombie script
	@public
*/
const getZombieAPI = scriptURI => {
	const modBrowserWindow = _modBrowserWindow;
	
	const controlGroup = modBrowserWindow.createControlGroup(scriptURI + '');
	
	const _createWindowInterface = window => {
		const target = Object.freeze({
			__proto__: null
			,
			/**
				@returns {Promise}
				@public
			*/
			close () {
				return new Promise((resolve, reject) => {
					try {
						window.close()
						.then(() => {
							resolve(true);
						})
						.catch(e => {
							reject('Failed to close a window');
						});
					} catch (e) {
						reject('Unknown internal error');
					}
				});
			}
			,
			/**
				@returns {Promise}
				@public
			*/
			waitForReload () {
				return new Promise((resolve, reject) => {
					try {
						window.waitForReload()
						.then(() => {
							resolve(true);
						})
						.catch(e => {
							reject('Failed to wait for a reload');
						});
					} catch (e) {
						reject('Unknown internal error');
					}
				});
			}
			,
			/**
				@returns {Promise}
				@public
			*/
			reload () {
				return new Promise((resolve, reject) => {
					try {
						window.reload()
						.then(() => {
							resolve(true);
						})
						.catch(e => {
							reject('Failed to reload');
						});
					} catch (e) {
						reject('Unknown internal error');
					}
				});
			}
			,
			/**
				@param {function} callback
				@param {...*} args
				@returns {Promise}
				@public
			*/
			runScript (callback, ... args) {
				return new Promise((resolve, reject) => {
					try {
						if ('function' != typeof callback) {
							throw new TypeError('Not a function');
						}
						
						window.runContentScript(callback, args)
						.then((results) => {
							resolve(results);
						})
						.catch(e => {
							reject('Script error: ' + e);
						});
					} catch (e) {
						reject('' + e);
					}
				});
			}
			,
			/**
				@type {boolean}
				@readonly
				@public
			*/
			get isPrivate () {
				return !!window.isPrivate;
			}
			,
			/**
				@type {string}
				@public
			*/
			get uri () {
				return '' + window.uri;
			}
			,
			set uri (uri) {
				window.uri = '' + uri;
				return true;
			}
		});
		
		const {proxy, revoke} = Proxy.revocable(target, Object.create(null));
		window._addCloseHandler(() => {
			revoke();
		});
		
		return Object.freeze(proxy);
	};
	
	return Object.freeze({
		__proto__: null
		,
		/**
			@param {string} uri
			@returns {Promise} Resolves to Window
			@public
		*/
		openWindow (uri) {
			return new Promise((resolve, reject) => {
				try {
					controlGroup.openWindow(uri ? uri + '' : void(0))
					.then(window => {
						resolve(_createWindowInterface(window));
					})
					.catch(e => {
						reject('Failed to open a normal window');
					});
				} catch (e) {
					reject('Unknown internal error');
				}
			});
		}
		,
		/**
			@param {string} uri
			@returns {Promise} Resolves to Window
			@public
		*/
		openPrivateWindow (uri) {
			return new Promise((resolve, reject) => {
				try {
					controlGroup.openWindow(uri ? uri + '' : void(0), true)
					.then(window => {
						resolve(_createWindowInterface(window));
					})
					.catch(e => {
						reject('Failed to open a private window');
					});
				} catch (e) {
					reject('Unknown internal error');
				}
			});
		}
		,
		/**
			Close all windows opened by the Zombie script
			@returns {Promise}
			@public
		*/
		closeAll () {
			return new Promise((resolve, reject) => {
				try {
					controlGroup.closeAll()
					.then(() => {
						resolve(true);
					})
					.catch(e => {
						reject('Failed to close windows');
					});
				} catch (e) {
					reject('Unknown internal error');
				}
			});
		}
	});
};


/* Exports */
exports.getZombieAPI = getZombieAPI;


// vim: ts=4 noet ai

